#include "playthread.h"
#include <SDL2/SDL.h>
#include <QFile>

/* 一些宏定义 */
// 采样率
#define SAMPLE_RATE 44100
// 采样格式
#define SAMPLE_FORMAT AUDIO_S16LSB
// 采样大小
#define SAMPLE_SIZE SDL_AUDIO_BITSIZE(SAMPLE_FORMAT)
// 声道数
#define CHANNELS 2
// 音频缓冲区的样本数量
#define SAMPLES 1024

#ifdef Q_OS_WIN
    #define FILENAME "C:/Users/zuo/Desktop/in.pcm"
#else
    #define FILENAME "/Users/zuojie/Desktop/in.pcm"
#endif

// 每个样本占用多少个字节
#define BYTES_PER_SAMPLE ((SAMPLE_SIZE * CHANNELS) / 8)
// 文件缓冲区的大小，例如：4096
#define BUFFER_SIZE (SAMPLES * BYTES_PER_SAMPLE)

PlayThread::PlayThread(QObject *parent) : QThread(parent){
    connect(this,&PlayThread::finished,&PlayThread::deleteLater);
}

PlayThread::~PlayThread(){
    disconnect();
    requestInterruption();
    quit();
    wait();
    qDebug() << this << "析构了";
}

int bufferLen;
char *bufferData;

/**
 * @brief pullAudioData
 * @param userdata SDL_AudioSpec.userdata
 * @param stream 音频缓冲区（需要将音频数据填充到这个缓冲区）
 * @param len 音频缓冲区的大小（SDL_AudioSpec.samples * 每个样本的大小）
 */
void pullAudioData(void *userdata,
                   // 需要往stream中填充PCM数据
                   Uint8 * stream,
                   // 希望填充的大小(samples * format * channels / 8)
                   int len){
    // 清空stream
    SDL_memset(stream, 0, len);

    // 文件数据还没准备好
    if (bufferLen <= 0) return;

    // 取len、bufferLen的最小值（为了保证数据安全，防止指针越界）
    len = (len > bufferLen) ? bufferLen : len;

    // 填充数据
    SDL_MixAudio(stream,(Uint8 *)bufferData,len,SDL_MIX_MAXVOLUME);
    bufferData += len;
    bufferLen -= len;
}

/*
SDL播放音频有2种模式：
Push（推）：【程序】主动推送数据给【音频设备】
Pull（拉）：【音频设备】主动向【程序】拉取数据 -- 采用这种
*/
void PlayThread::run(){
    // 初始化Audio子系统
    if(SDL_Init(SDL_INIT_AUDIO) < 0){
        SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
        return;
    }

    // 音频参数
    SDL_AudioSpec spec;
    // 采样率
    spec.freq = SAMPLE_RATE;
    // 声道数
    spec.channels = CHANNELS;
    // 采样格式（s16le）
    spec.format = SAMPLE_FORMAT;
    // 音频缓冲区的样本数量（这个值必须是2的幂）
    spec.samples = SAMPLES;
    // 回调
    spec.callback = pullAudioData;

    // 打开音频设备
    if (SDL_OpenAudio(&spec, nullptr)) {
        qDebug() << "SDL_OpenAudio Error" << SDL_GetError();
        // 清除所有初始化的子系统
        SDL_Quit();
        return;
    }

    QFile file(FILENAME);
    if(!file.open(QFile::ReadOnly)){
        qDebug() << "文件打开失败" << FILENAME;
        // 关闭音频设备
        SDL_CloseAudio();
        // 清除所有初始化的子系统
        SDL_Quit();
        return;
    }

    // 开始播放(0是取消暂停)
    SDL_PauseAudio(0);

    // 存放从文件中读取的数据
    char data[BUFFER_SIZE];
    while (!isInterruptionRequested()) {
        bufferLen = file.read(data,BUFFER_SIZE);

        // 文件数据已经读取完毕
        if (bufferLen <= 0) break;
        // 读取到了文件数据
        bufferData = data;

        // 等待音频数据填充完毕

        while (bufferLen > 0) {
            SDL_Delay(1);// 睡眠1毫秒
        }
    }

    // 关闭文件
    file.close();
    // 关闭音频设备
    SDL_CloseAudio();
    // 清除所有初始化的子系统
    SDL_Quit();
}
